home *** CD-ROM | disk | FTP | other *** search
- /*
- * rplayd.c
- *
- * Copyright (c) 1992 by Mark Boyns
- *
- * Permission to use, copy, modify, and distribute this software and its
- * documentation for any purpose and without fee is hereby granted, provided
- * that the above copyright notice appear in all copies and that both that
- * copyright notice and this permission notice appear in supporting
- * documentation. This software is provided "as is" without express or
- * implied warranty.
- */
-
- #include <sys/types.h>
- #include <sys/time.h>
- #include <sys/file.h>
- #include <sys/param.h>
- #include <sys/stat.h>
- #include <sys/mman.h>
- #include <sys/socket.h>
- #include <sys/signal.h>
- #include <sys/fcntl.h>
- #include <lwp/lwp.h>
- #include <lwp/stackdep.h>
- #include <netinet/in.h>
- #include <stdio.h>
- #include <search.h>
- #include <strings.h>
- #include "libst.h"
- #include "rplay.h"
-
- /*
- * The defines below can be used to customize rplayd.
- */
- #define MAX_SOUNDS 1024 /* maximum sounds that rplayd can handle */
- /* this must be more than the sounds in rplay.conf */
- #define SPOOL_SIZE 8 /* number of sounds that can be played at once */
- #define SOUND_LIST_SIZE 32 /* maximum size of a sound list */
- #define AUDIO_BUFSIZE 500 /* rplayd audio buffer size */
- #define TIME_SLICE 50000 /* micro seconds */
- #define RPLAYD_TIMEOUT 6000 /* 50000usec = 1/20sec, 20*5*60 = 5 mins */
- #define AUDIO_CLOSE_TIMEOUT 100 /* close audio device when not in use */
- /* 50000usec = 1/20sec, 20*5 = 5 secs */
-
- /*
- * These should not be changed
- */
- #define MINPRIO 1
- #define MAXPRIO 10
- #define SUN_AUDIO_DEVICE "/dev/audio"
- #define SUN_MAGIC 0x2e736e64
- #define SUN_HDRSIZE 24
-
- typedef struct sound {
- char *name; /* name of the sound file */
- char path[MAXPATHLEN]; /* pathname of the sound file */
- char *buf; /* the sound buffer */
- char *start; /* where to start */
- char *stop; /* where to stop */
- int size; /* sizeof the sound buffer */
- } Sound;
-
- typedef struct spool {
- int nsounds; /* nsounds in the sound list */
- int curr; /* current playing sound in the list */
- int state; /* state of the current sound */
- Sound *slist[SOUND_LIST_SIZE];/* the sound list */
- int vlist[SOUND_LIST_SIZE]; /* the volume list */
- char *ptr; /* sound buffer pointer */
- char *end; /* the end of the sound buffer */
- } Spool;
-
- Spool spool[SPOOL_SIZE]; /* the sound spool */
- Sound *list[SOUND_LIST_SIZE]; /* temporary list used by the server */
- char recvbuf[MAX_PACKET]; /* buffer for incoming packets */
-
- ENTRY *hsearch();
- Sound *lookup();
- int scheduler(), player(), server();
- int in = 0, out = 0;
- int audio_fd = -1;
-
- main()
- {
- config();
- spool_init();
-
- pod_setmaxpri(MAXPRIO);
- lwp_setstkcache(4096, 4);
- lwp_create((thread_t *)0, scheduler, MAXPRIO, 0, lwp_newstk(), 0);
- lwp_create((thread_t *)0, player, MINPRIO, 0, lwp_newstk(), 0);
- lwp_create((thread_t *)0, server, MINPRIO, 0, lwp_newstk(), 0);
-
- exit(0);
- }
-
- config()
- {
- Sound *s;
- ENTRY e;
- FILE *fp;
- char buf[MAXPATHLEN], *p;
-
- fp = fopen(RPLAY_CONF, "r");
- if (fp == NULL) {
- fprintf(stderr, "rplayd: cannot open %s\n", RPLAY_CONF);
- exit(1);
- }
-
- if (hcreate(MAX_SOUNDS) == 0) {
- fprintf(stderr, "rplayd: cannot create hash table\n");
- exit(1);
- }
-
- while(fgets(buf, sizeof(buf), fp) != NULL) {
- if (buf[0] == '#') {
- continue;
- }
-
- s = (Sound *)malloc(sizeof(Sound));
- sscanf(buf, "%s", s->path);
- p = rindex(s->path, '/');
- s->name = p == NULL ? s->path : p+1;
- s->buf = NULL;
- s->size = 0;
-
- e.key = s->name;
- e.data = (char *)s;
- if (hsearch(e, ENTER) == NULL) {
- fprintf(stderr, "rplayd: the hash table is full, too many sounds\n");
- exit(1);
- }
- }
-
- fclose(fp);
- }
-
- spool_init()
- {
- int i;
-
- for(i = 0; i < SPOOL_SIZE; i++) {
- spool_clear(i);
- }
- }
-
- Sound *lookup(name)
- char *name;
- {
- ENTRY e, *found;
- Sound *s;
-
- e.key = name;
- found = hsearch(e, FIND);
- if (found == NULL) {
- return NULL;
- }
-
- s = (Sound *)found->data;
-
- if (s->buf == NULL) {
- struct stat st;
- long magic, hdr_size;
- int fd;
-
- fd = open(s->path, O_RDONLY, 0);
- if (fd < 0) {
- return NULL;
- }
-
- if (fstat(fd, &st) < 0) {
- return NULL;
- }
-
- s->size = st.st_size;
-
- /*
- * use mmap to load the sound
- */
- s->buf = mmap(0, s->size, PROT_READ, MAP_SHARED, fd, 0);
- if (s->buf == (caddr_t)-1) {
- return NULL;
- }
-
- /*
- * make sure it is a Sun audio file
- */
- magic = *((long *)s->buf);
- if (magic != SUN_MAGIC) {
- return NULL;
- }
-
- /*
- * ignore the header
- */
- hdr_size = *((long *)s->buf + 1);
- if (hdr_size < SUN_HDRSIZE) {
- return NULL;
- }
-
- s->start = s->buf + hdr_size;
- s->stop = s->buf + s->size - 1;
-
- close(fd);
- }
-
- return s;
- }
-
- server()
- {
- int sock_fd, x, restarted, len;
- struct sockaddr_in s, f;
- int flen = sizeof(f);
- char *p;
- int attr, i, n, j;
- int found;
- Sound *sound;
-
- #ifdef INETD
- sock_fd = 0;
- #else
- bzero(&s, sizeof(s));
- s.sin_family = AF_INET;
- s.sin_port = htons(RPLAY_PORT);
- s.sin_addr.s_addr = INADDR_ANY;
-
- sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
- if (sock_fd < 0) {
- perror("socket");
- pod_exit(1);
- }
-
- if (bind(sock_fd, &s, sizeof(s)) < 0) {
- perror("bind");
- pod_exit(1);
- }
- #endif INETD
-
- for(;;) {
- len = recvfrom(sock_fd, recvbuf, sizeof(recvbuf), 0, &f, &flen);
- p = recvbuf;
- attr = *p++;
- switch(attr) {
- case RPLAY_PLAY:
- for(i = 0; i < SPOOL_SIZE; i++) {
- if (spool[i].state == RPLAY_NULL) {
- break;
- }
- }
- if (i == SPOOL_SIZE) {
- break;
- }
- do {
- sound = lookup(p);
- if (sound == NULL) {
- spool_clear(i);
- break;
- }
- p += strlen(p) + 1;
- spool[i].slist[spool[i].nsounds] = sound;
- spool[i].vlist[spool[i].nsounds] = (unsigned char)*p++;
- spool[i].nsounds++;
- } while(*p != NULL);
- if (sound != NULL) {
- spool[i].ptr = spool[i].slist[0]->start;
- spool[i].end = spool[i].slist[0]->stop;
- spool[i].curr = 0;
- spool[i].state = attr;
- in++;
- }
- break;
-
- case RPLAY_STOP:
- case RPLAY_PAUSE:
- case RPLAY_CONTINUE:
- n = 0;
- do {
- list[n] = lookup(p);
- if (list[n] == NULL) {
- break;
- }
- n++;
- p += strlen(p) + 1;
- } while(*p != NULL);
- if (list[n-1] == NULL) {
- break;
- }
- for(i = 0; i < SPOOL_SIZE; i++) {
- if (spool[i].nsounds == n) {
- found = 1;
- for(j = 0; j < n; j++) {
- if (list[j] != spool[i].slist[j]) {
- found = 0;
- break;
- }
- }
- if (found) {
- spool[i].state = attr;
- break;
- }
- }
- }
- break;
-
- default:
- fprintf(stderr, "rplayd: unknown rplay attribute (0x%0x)\n", attr);
- break;
- }
- }
- }
-
- scheduler()
- {
- struct timeval t;
- int cnt;
-
- cnt = 0;
- t.tv_sec = 0;
- t.tv_usec = TIME_SLICE;
-
- for(;;) {
- if (in == out) {
- cnt++;
- switch(cnt) {
- case RPLAYD_TIMEOUT:
- pod_exit(0);
-
- case AUDIO_CLOSE_TIMEOUT:
- if (audio_fd != -1) {
- close(audio_fd);
- audio_fd = -1;
- }
- break;
- }
- }
- else {
- cnt = 0;
- }
- lwp_sleep(&t);
- lwp_resched(MINPRIO);
- }
- }
-
- player()
- {
- int i, index, empty;
- long total;
- long val;
- char buf[AUDIO_BUFSIZE];
-
- index = 0;
-
- for(;;) {
- total = 0;
- empty = 1;
- for(i = 0; i < SPOOL_SIZE; i++) {
- switch(spool[i].state) {
- case RPLAY_CONTINUE:
- spool[i].state = RPLAY_PLAY;
- case RPLAY_PLAY:
- empty = 0;
- val = st_ulaw_to_linear((unsigned char)*spool[i].ptr) * spool[i].vlist[spool[i].curr];
- total += val >> 7;
- if (spool[i].ptr == spool[i].end) {
- spool[i].curr++;
- if (spool[i].curr == spool[i].nsounds) {
- spool_clear(i);
- out++;
- }
- else {
- spool[i].ptr = spool[i].slist[spool[i].curr]->start;
- spool[i].end = spool[i].slist[spool[i].curr]->stop;
- }
- }
- else {
- spool[i].ptr++;
- }
- break;
-
- case RPLAY_STOP:
- spool_clear(i);
- out++;
- break;
-
- default:
- break;
- }
- }
-
- if (empty) {
- if (index > 0) {
- if (audio_fd == -1) {
- audio_fd = open(SUN_AUDIO_DEVICE, O_WRONLY | O_NDELAY, 0);
- }
- if (audio_fd != -1) {
- write(audio_fd, buf, index);
- }
- index = 0;
- }
- lwp_yield(SELF);
- }
- else {
- buf[index++] = st_linear_to_ulaw(total);
- if (index == AUDIO_BUFSIZE) {
- if (audio_fd == -1) {
- audio_fd = open(SUN_AUDIO_DEVICE, O_WRONLY | O_NDELAY, 0);
- }
- if (audio_fd != -1) {
- write(audio_fd, buf, index);
- }
- index = 0;
- }
- }
- }
- }
-
- spool_clear(i)
- int i;
- {
- spool[i].curr = 0;
- spool[i].nsounds = 0;
- spool[i].ptr = NULL;
- spool[i].end = NULL;
- spool[i].state = RPLAY_NULL;
- }
-